home *** CD-ROM | disk | FTP | other *** search
-
- /*© Copyright 1989-1992 UserLand Software, Inc. All Rights Reserved.*/
-
- #include <FinderMenuInterface.h>
- #include <Utils.h>
-
- #include <processes.h>
- #include <Menus.h>
- #include <GestaltEqu.h>
- #include <iac.h>
- #include <menusharing.h>
-
- tyMSglobals MSglobals; /*Menu Sharing globals, all in one struct*/
-
- static pascal Boolean ProcessInForeground()
- {
- /*
- return true if we're running in the foreground, false if we're in the
- background.
- */
-
- ProcessSerialNumber currentprocess, frontprocess;
- Boolean fl;
-
- GetCurrentProcess(¤tprocess);
-
- GetFrontProcess(&frontprocess);
-
- SameProcess(¤tprocess, &frontprocess, &fl);
-
- return(fl);
- } /*ProcessInForeground*/
-
- static Boolean FinderInForeground()
- {
- return GetFrontProcessCreator() == 'MACS';
- // 'FNDR', 'MACS'
- }
-
- static Boolean ServerIsRunning(void)
- {
- return IsTargetRunning(MSglobals.serverid, nil);
- } /*ServerIsRunning*/
-
-
- static short CountMenuArray(void)
- {
- /*
- return the number of menus in the menu array.
- */
-
- reg hdlmenuarray hm = MSglobals.hsharedmenus;
-
- if (hm == nil)
- return(0);
-
- return((short) (GetHandleSize((Handle) hm) / sizeof(tysharedmenurecord)));
- } /*CountMenuArray*/
-
-
- static pascal Boolean InstallSharedMenus(short idmenuafter)
- {
- /*
- insert all of the menus in the menuarray into the menu bar. main
- menus are inserted in front of idmenuafter. if idmenuafter is zero,
- main(non-hierarchic) menus will be added to the right of all others.
- */
-
- reg hdlmenuarray hm = MSglobals.hsharedmenus;
- reg short i, ct;
- tysharedmenurecord *pItem;
-
- FMRollBeachball();
-
- ct = CountMenuArray();
-
- HLock(hm);
-
- for(i = 0; i < ct; i++) {
- pItem = &(**hm) [i];
-
- if (pItem->flhierarchic) {
- if (! FMAppend(pItem->hmenu, -1)) {
- #ifdef DEBUG
- DebugStr("\pfailed to insert!");
- #endif
- }
- } else {
- if (! FMAppend(pItem->hmenu, idmenuafter)) {
- #ifdef DEBUG
- DebugStr("\pfailed to insert!");
- #endif
- }
- }
-
- pItem->flinserted = true; /*so we'll know it needs to be removed*/
- } /*for*/
-
- HUnlock(hm);
-
- FMFreshMenuBar();
-
- return(true);
- } /*InstallSharedMenus*/
-
-
- static short GetMenuHandles(void)
- {
- /*
- loop through the menuarray, send an IAC message to the menu server requesting
- that each MenuHandle be sent to us.
- */
-
- reg hdlmenuarray hm = MSglobals.hsharedmenus;
- reg short i, ct;
- AppleEvent event, reply;
- reg short fl;
- long id;
- MenuHandle hmenu;
-
- ct = CountMenuArray();
-
- for(i = 0; i < ct; i++) {
- if (! IACnewverb(MSglobals.serverid, MSglobals.serverid, 'gmhd', &event))
- return(false);
-
- IACglobals.event = &event;
-
- if (! IACpushlongparam(MSglobals.clientid, 'menp'))
- return(false);
-
- if (! IACpushshortparam(i, 'idix'))
- return(false);
-
- if (! IACsendverb(IACglobals.event, &reply))
- return(false);
-
- IACglobals.reply = &reply;
-
- IACglobals.event = &reply;
-
- fl = IACgetbinaryparam(keyDirectObject, (Handle *) &hmenu);
-
- IACdisposeverb(&reply);
-
- if (! fl)
- return(false);
-
- (**hm)[i].hmenu = hmenu;
- } /*for*/
-
- return(true);
- } /*GetMenuHandles*/
-
-
- static pascal Boolean GetSharedMenus(short firstresource)
- {
- /*
- call the menu server to get a menuarray, keyed off of our application id.
-
- firstresource is the starting id to be used for the menus; if there are
- n menus, their ids will range from firstresource to firstresource + n - 1.
- */
-
- AppleEvent event, reply;
- reg short fl;
- OSType id;
-
- if (! IACnewverb(MSglobals.serverid, MSglobals.serverid, 'gmry', &event))
- return(false);
-
- IACglobals.event = &event;
-
- if (! IACpushlongparam(MSglobals.clientid, 'menp'))
- return(false);
-
- if (! IACpushshortparam(firstresource, 'res1'))
- return(false);
-
- if (! IACsendverb(&event, &reply))
- return(false);
-
- IACglobals.event = &reply;
-
- fl = IACgetbinaryparam(keyDirectObject,(Handle *) &MSglobals.hsharedmenus);
-
- IACdisposeverb(&reply);
-
- if (! fl)
- return(false);
-
- return(GetMenuHandles());
- } /*GetSharedMenus*/
-
-
- pascal Boolean DisposeSharedMenus(void)
- {
- /*
- completely dispose of the menuarray and the menu handles it contains.
-
- 10/10/91 DW: check for no shared menus before disposing, save code if
- its ever called from more than one place. also set the global handle to
- nil after disposing and redraw the menu bar.
- */
-
- reg hdlmenuarray hm = MSglobals.hsharedmenus;
- reg short i;
- reg short ctmenus;
-
- if (hm == nil) /*no shared menus to toss*/
- return(true);
-
- FMDeleteMenus();
-
- ctmenus = CountMenuArray();
-
- for(i = 0; i < ctmenus; i++) {
- DisposeMenu((**hm) [i].hmenu);
- } /*for*/
-
- DisposHandle((Handle) hm);
-
- MSglobals.hsharedmenus = nil;
-
- FMFreshMenuBar();
-
- return(true);
- } /*DisposeSharedMenus*/
-
- #if 0
-
- pascal Boolean IsSharedMenu(short idmenu)
- {
- /*
- return true if the indicated menu is one of the shared menus.
- */
-
- reg hdlmenuarray hm = MSglobals.hsharedmenus;
- reg short ct, i;
- tysharedmenurecord item;
-
- ct = CountMenuArray();
-
- for (i = 0; i < ct; i++) {
- if ((**hm) [i].idmenu == idmenu)
- return(true);
- } /*for*/
-
- return(false);
- } /*IsSharedMenu*/
-
- #else
-
- pascal Boolean IsSharedMenu(short idmenu)
- {
- return true;
- }
-
- #endif
-
- #if 0
- pascal Boolean EnableSharedMenus(Boolean flenable) {
-
- /*
- Enables or disables the the menus in the specified menu array.
-
- Always returns true.
- */
-
- reg hdlmenuarray hm = MSglobals.hsharedmenus;
- reg short i;
- reg short ctmenus;
- reg MenuHandle hmenu;
-
- ctmenus = CountMenuArray();
-
- for(i = 0; i < ctmenus; i++) {
-
- hmenu =(**hm) [i].hmenu;
-
- if (flenable)
- EnableItem(hmenu, 0);
- else
- DisableItem(hmenu, 0);
- } /*for*/
-
- DrawMenuBar();
-
- return(true);
- } /*EnableSharedMenus*/
- #endif
-
- pascal Boolean RunSharedMenuItem(short idmenu, short iditem)
- {
- /*
- call the menu server to run the script linked to the indicated menu item.
- the script will execute asynchonously, after this call returns.
- */
-
- AppleEvent event, reply;
- OSType id;
- Boolean fl;
- long refcon;
- if (! IACnewverb(MSglobals.serverid, MSglobals.serverid, 'runm', &event))
- return(false);
-
- IACglobals.event = &event;
-
- if (! IACpushlongparam(MSglobals.clientid, 'menp'))
- return(false);
-
- if (! IACpushshortparam(idmenu, 'mid '))
- return(false);
-
- if (! IACpushshortparam(iditem, 'mitm'))
- return(false);
-
- if (! IACsendverb(&event, &reply))
- return(false);
-
- IACglobals.event = &reply;
-
- fl = IACgetlongparam(keyDirectObject, &refcon);
-
- IACdisposeverb(&reply);
-
- return(fl &&(refcon != 0));
- } /*RunSharedMenuItem*/
-
-
- pascal Boolean CheckSharedMenus(idinsertafter) short idinsertafter;
- {
- /*
- call this from your main event loop after receiving and processing every
- event. if the menus need updating, we send a message to the server asking
- for our shared menus.
-
- if we load menus, they are assigned resource ids starting with idinsertafter.
- this number must be less than 255 to allow for hierarchic menus, and must be
- small enough so that no menu has an id of greater than 255.
-
- 9/28/91 DW: only update menus if we're the front process. this catches the
- delay on re-loading a changed menu structure on the Multifinder switch. No
- extra burden on the script writer editing the menu bar.
- */
-
- if (! MSglobals.fldirtysharedmenus) /*no need for an update, return quickly*/
- return(true);
-
- if (! FinderInForeground())
- return true;
-
- #if 0
- if (! ProcessInForeground()) /*only update menus if we're the front process*/
- return(true);
- #endif
-
- DisposeSharedMenus();
-
- if (! ServerIsRunning())
- MSglobals.fldirtysharedmenus = false;
- else {
- if (GetSharedMenus(idinsertafter)) {
- InstallSharedMenus(0); /*install to the right of all other menus*/
- }
- MSglobals.fldirtysharedmenus = false;
- }
-
- return(true);
- } /*CheckSharedMenus*/
-
-
- pascal Boolean SharedScriptRunning()
- {
- /*
- returns true if a shared script is currently running, false otherwise.
- it's provided so that an application can intelligently handle cmd-period
- script termination in its keystroke handling routine.
- */
-
- return (MSglobals.flscriptrunning);
- } /*SharedScriptRunning*/
-
-
- pascal Boolean CancelSharedScript()
- {
- /*
- call this when the user presses cmd-period or otherwise indicates to you that
- he or she wants the currently running script to be halted. we record the fact
- in the globals record. the next time we receive a message from the menu server
- we'll send back an error, indicating that the script has been cancelled.
- */
-
- if (MSglobals.flscriptrunning)
- MSglobals.flscriptcancelled = true;
-
- return (true);
- } /*CancelSharedScript*/
-
-
- pascal Boolean SharedMenuHit(idmenu, iditem) short idmenu, iditem;
- {
- /*
- returns true if the indicated menu and item indicate a shared menu item.
-
- if not, we return false -- the item is in one of your menus, you should
- process the command as you normally would.
-
- we send an IAC message to the menu server, requesting that the script
- linked into that item be run.
-
- we disable the shared menus, awaiting a 'done' message to re-enable them.
- */
-
- if (! IsSharedMenu(idmenu)) /*not a shared menu*/
- return(false);
-
- // HiliteMenu(0);
-
- if (RunSharedMenuItem(idmenu, iditem)) {
- MSglobals.flscriptrunning = true;
- // EnableSharedMenus(false);
- } else {
- FMFinishedProcessing();
- }
-
- return(true);
- } /*SharedMenuHit*/
-
-
- pascal Boolean SharedScriptCancelled(event, reply)
- AppleEvent *event, *reply;
- {
-
- /*
- call this routine in each Apple event message handler that could conceivably
- be used in a script being run by the menu server. if we return false continue
- processing the message as you normally would. if we return true, that means
- that the script that's running has been cancelled by the user; you should
- return noErr from your Apple event handler when we return true.
-
- before we return true, we reply to the message on behalf of the message
- handler. we send a specific error code of 6, this should be interpreted by
- the scripting system as "stop running the script, but don't display an
- error dialog.
-
- we admit this mechanism is somewhat klunky, but it proved too difficult to have
- Frontier be ready to respond to a "Cancel Script" Apple event while running
- the script and also giving time slices to agents.
-
- 10/21/91 DW: thanks to Kevin Calhoun(Apple) we can tell who sent the message.
- so we only reply with an error if the message arrived from the shared menu
- server. it's nice to close this loop!
- */
-
- OSType sender;
- Str255 s;
-
- if (MSglobals.flscriptcancelled && MSglobals.flscriptrunning) {
- IACglobals.event = event;
-
- if (IACgetsender() == MSglobals.serverid) { /*sender is shared menu server*/
- MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
- s[0] = (char) 0; /*set length to 0*/
- IACglobals.reply = reply;
- IACreturnerror(6, s); /*server watches for this special error code*/
- return(true);
- }
- }
-
- return(false); /*script not cancelled, keep processing message*/
- } /*SharedScriptCancelled*/
-
-
- static pascal OSErr HandleMenuDirty(event, reply, refcon)
- AppleEvent *event, *reply;
- long refcon;
- {
- /*
- this Apple event handler is called when the application's menu bar has been
- edited by the script writer in the menu server's menu editor.
-
- we just record the dirty-ness of the menus in a boolean, we'll actually re-
- load the menus when we become the foreground process.
- */
-
- MSglobals.fldirtysharedmenus = true;
-
- return(noErr);
- } /*HandleMenuDirty*/
-
-
- static pascal OSErr HandleScriptComplete(event, reply, refcon)
- AppleEvent *event, *reply;
- long refcon;
- {
- /*
- this Apple event handler is called when a menu script has completed running.
-
- we update a couple of menu-sharing globals and re-enable the shared menus.
-
- 10/8/91 DW: added callback to support Applet Manager.
- */
-
- MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
-
- // EnableSharedMenus(true);
-
- if (MSglobals.scriptcompletedcallback != nil)
- return (*MSglobals.scriptcompletedcallback)(event, reply, refcon);
-
- return(noErr);
- } /*HandleScriptComplete*/
-
-
- pascal Boolean InitSharedMenus()
- {
- /*
- sets the program up for menu sharing. we initialize the fields of MSglobals.
-
- then we get the creator id of the application we're running inside of. the menu
- sharing server will need this information to be passed in an IAC message when
- we're requesting our menus.
-
- next, we check to see if we're running on a version of the Mac OS that supports
- Apple events. if not, we return false. otherwise we install two Apple event
- message handlers -- one to catch the "menu needs update" message, and another
- to handle the "script has completed" message.
- */
-
- MSglobals.serverid = 'LAND'; /*Frontier's creator id*/
- MSglobals.clientid = 0;
- MSglobals.hsharedmenus = nil; /*haven't loaded shared menus yet*/
- MSglobals.fldirtysharedmenus = true; /*force update 1st time thru event loop*/
- MSglobals.flscriptcancelled = false; /*script hasn't been cancelled*/
- MSglobals.flscriptrunning = false; /*no menu script running*/
- MSglobals.clientid = GetProcessCreator();
- MSglobals.scriptcompletedcallback = nil;
-
- if (! IACinit()) /*Apple events aren't present, or otherwise couldn't init*/
- return(false);
-
- if (! IACinstallhandler(MSglobals.clientid, 'updm',(ProcPtr) &HandleMenuDirty))
- return(false);
-
- if (! IACinstallhandler(MSglobals.clientid, 'done',(ProcPtr) &HandleScriptComplete))
- return(false);
-
- return(true);
- } /*InitSharedMenus*/
-
-
-